﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Xml;
using System.Xml.Serialization;

namespace ClassifierLib
{

    /// <summary>
    /// This is a special class which allows the keys of the dictionary to be databound
    /// </summary>
    [XmlRoot("BindingDictionary")]
    public class BindingDictionary : Dictionary<string, double>, ICustomTypeDescriptor, IXmlSerializable
    {
        #region Special Sauce to allow easy databinding to Statistics elements
        // For more information about how this works see:
        // http://home.scarlet.be/thehive/DataVirtualization.pdf 

        #region ICustomTypeDescriptor Members

        public AttributeCollection GetAttributes()
        {
            return TypeDescriptor.GetAttributes(this.GetType());
        }

        public string GetClassName()
        {
            return TypeDescriptor.GetClassName(this.GetType());
        }

        public string GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this);
        }

        public TypeConverter GetConverter()
        {
            return TypeDescriptor.GetConverter(this.GetType());
        }

        public EventDescriptor GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(this.GetType());
        }

        public PropertyDescriptor GetDefaultProperty()
        {
            return TypeDescriptor.GetDefaultProperty(this.GetType());
        }

        public object GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(this.GetType(), editorBaseType);
        }

        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this.GetType(), attributes);
        }

        public EventDescriptorCollection GetEvents()
        {
            return TypeDescriptor.GetEvents(this.GetType());
        }

        private PropertyDescriptorCollection m_PropertyDescriptorCollectionCache=null;
        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            if (m_PropertyDescriptorCollectionCache == null)
            {
                PropertyDescriptor[] properties = new PropertyDescriptor[this.Count];
                int i = 0; foreach (string key in this.Keys)
                {
                    properties[i] = new MyCustomClassPropertyDescriptor(key);
                    i++;
                }
                m_PropertyDescriptorCollectionCache = new PropertyDescriptorCollection(properties);
            } 
            return m_PropertyDescriptorCollectionCache;
        }

        public PropertyDescriptorCollection GetProperties()
        {
            return GetProperties(null);
        }

        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }

        public class MyCustomClassPropertyDescriptor : PropertyDescriptor
        {    
            public MyCustomClassPropertyDescriptor(string key) : base(key, null)
            {
            }
            public override bool CanResetValue(object component)
            {
                return false;    
            }
            public override Type ComponentType
            {        
                get 
                { 
                    return typeof(Dictionary<string, double>);
                }
            }
            public override object GetValue(object component)    
            {        
                return ((Dictionary<string, double>)component)[base.Name];
            }
            public override bool IsReadOnly    
            {        
                get 
                { 
                    return false; 
                }
            }        
            public override Type PropertyType    
            {        
                get 
                { 
                    return typeof(double); 
                }    
            }
            public override void ResetValue(object component)    
            {        
                ((Dictionary<string, double>)component)[base.Name] = 0;
            }        
            public override void SetValue(object component, object value)    
            {        
                ((Dictionary<string, double>)component)[base.Name] = (double)value;
            }        
            public override bool ShouldSerializeValue(object component)    
            {        
                return false;    
            }
        }
        #endregion
        #endregion

        #region IXmlSerializable Members

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            throw new NotImplementedException();
        }

        public void ReadXml(System.Xml.XmlReader reader)
        {
            Boolean wasEmpty = reader.IsEmptyElement;
            
            reader.Read(); 
            
            if (wasEmpty)
            { 
                return; 
            } 
            while (reader.NodeType != XmlNodeType.EndElement) 
            { 
                if (reader.Name == "Item") 
                { 
                    String key = reader.GetAttribute("Key"); 
                    Type type = Type.GetType(reader.GetAttribute("TypeName")); 
                    reader.Read(); 
                    
                    if (type != null) 
                    { 
                        this.Add(key, (double)(new XmlSerializer(type).Deserialize(reader)));
                    } 
                    else 
                    { 
                        reader.Skip();
                    } 
                    reader.ReadEndElement(); 
                    reader.MoveToContent(); 
                } 
            } 
            reader.ReadEndElement();

        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            foreach (KeyValuePair<String, double> item in this) 
            { 
                writer.WriteStartElement("Item"); 
                writer.WriteAttributeString("Key", item.Key); 
                writer.WriteAttributeString("TypeName", item.Value.GetType().AssemblyQualifiedName);
                new XmlSerializer(item.Value.GetType()).Serialize(writer, item.Value); 
                writer.WriteEndElement(); 
            }

        }

        #endregion
    }
}
